
#include <string.h>
#include "rtthread.h"
#include "ev_packet.h"
#include "ev_utils.h"
#include "ev_test.h"

#ifdef RT_USING_FINSH
#include "shell.h"
#ifdef EV_BUILD_TEST

static int MakePacketValidTest(void) {
    uint8_t data[EV_PACKET_MAX_LEN];
    uint32_t out_len;

    uint8_t test_data[] = {0x01, 0x02, 0x03};
    ev_packet_t pkt;
    memcpy(pkt.data, test_data, sizeof(test_data));
    pkt.cmd = 0xF1;
    pkt.seq = 0xF2;
    pkt.user = 0xF3;
    pkt.len = sizeof(test_data);
    int result = ev_packet_make(&pkt, data, &out_len);

    EXPECT_EQ(result, 0);
    EXPECT_EQ(out_len, pkt.len + EV_PACKET_TAIL_LEN);

    // Check if data is correctly packed
    EXPECT_EQ(memcmp(data, test_data, pkt.len), 0);
    EXPECT_EQ(data[pkt.len + 0], EV_PACKET_SOF);
    EXPECT_EQ(data[pkt.len + 1], pkt.user);
    EXPECT_EQ(data[pkt.len + 2], pkt.seq);
    EXPECT_EQ(data[pkt.len + 3], pkt.cmd & 0xff);
    EXPECT_EQ(data[pkt.len + 4], (pkt.cmd>>8) & 0xff);
    EXPECT_EQ(data[pkt.len + 5], (pkt.len) & 0xff);
    EXPECT_EQ(data[pkt.len + 6], (pkt.len>>8) & 0xff);
    uint8_t sum = 0;
    for (uint32_t i = 0; i < 7; i ++) {
        sum += data[pkt.len + i];
    }
    EXPECT_EQ(data[pkt.len + 7], (uint8_t)((~sum) + 1));
    EXPECT_EQ(ev_crc16(data, out_len, EV_PACKET_MAGIC), 0);

    return 0;
}

// Test ev_packet_make with error parameters
static int MakePacketErrorParam(void)
{
    uint8_t data[EV_PACKET_MAX_LEN];
    uint32_t out_len;
    ev_packet_t pkt;
    pkt.cmd = 0xF1;
    pkt.seq = 0xF2;
    pkt.user = 0xF3;
    pkt.len = 0;

    int result = ev_packet_make(&pkt, data, &out_len); // data len is 0
    EXPECT_EQ(result, 0);
    EXPECT_EQ(out_len, EV_PACKET_TAIL_LEN);
    EXPECT_EQ(ev_crc16(data, out_len, EV_PACKET_MAGIC), 0);

    result = ev_packet_make(&pkt, NULL, &out_len);  // NULL data pointer
    EXPECT_EQ(result, -1);

    result = ev_packet_make(&pkt, data, NULL);      // NULL length pointer
    EXPECT_EQ(result, -1);

    pkt.len = EV_PACKET_MAX_DATA_LEN + 1;           // Invalid length
    result = ev_packet_make(&pkt, data, NULL);
    EXPECT_EQ(result, -1);

    pkt.len = EV_PACKET_MAX_DATA_LEN;               // Valid length
    result = ev_packet_make(&pkt, data, &out_len);
    EXPECT_EQ(result, 0);
    EXPECT_EQ(out_len, EV_PACKET_MAX_LEN);
    EXPECT_EQ(ev_crc16(data, out_len, EV_PACKET_MAGIC), 0);

    return 0;
}

// Test ev_packet_check with valid packet
static int CheckPacketValid(void) {
    uint8_t buffer[EV_PACKET_MAX_LEN];

    // Manually create a valid packet
    uint8_t test_data[] = {0x01, 0x02, 0x03};
    uint32_t packet_len = sizeof(test_data);
    memcpy(buffer, test_data, packet_len);
    buffer[packet_len + 0] = EV_PACKET_SOF;
    buffer[packet_len + 1] = 0xF1;  //user
    buffer[packet_len + 2] = 0xF2;  // seq
    buffer[packet_len + 3] = 0xF3;  // cmd low byte
    buffer[packet_len + 4] = 0;     // cmd high byte
    buffer[packet_len + 5] = 3;     // len low byte
    buffer[packet_len + 6] = 0;     // len high byte
    buffer[packet_len + 7] = 0;     // sum
    for (uint32_t i = packet_len; i < packet_len + 7; i ++) {
        buffer[packet_len + 7] += buffer[i];
    }
    buffer[packet_len + 7] = (uint8_t) (-buffer[packet_len + 7]);
    uint16_t crc = ev_crc16(buffer, packet_len + 8, EV_PACKET_MAGIC);
    buffer[packet_len + 8] = crc & 0xff;
    buffer[packet_len + 9] = (crc >> 8) & 0xff;

    ev_packet_t pkt;
    int result = ev_packet_check(buffer, packet_len + EV_PACKET_TAIL_LEN, &pkt);
    EXPECT_EQ(result, 0);
    EXPECT_EQ(pkt.user, 0xF1);
    EXPECT_EQ(pkt.seq, 0xF2);
    EXPECT_EQ(pkt.cmd, 0xF3);
    EXPECT_EQ(pkt.len, packet_len);
    EXPECT_EQ(memcmp(pkt.data, test_data, packet_len), 0);

    return 0;
}

// Test ev_packet_check with too short packet
static int CheckPacketTooShort(void) {
    uint8_t buffer[EV_PACKET_MAX_LEN] = {0}; // Less than minimum EV_PACKET_TAIL_LEN bytes
    int result = ev_packet_check(buffer, EV_PACKET_TAIL_LEN - 1, NULL);
    EXPECT_EQ(result, -1);
    result = ev_packet_check(buffer, EV_PACKET_TAIL_LEN, NULL);  //crc error
    EXPECT_EQ(result, -2);
    return 0;
}

// Test ev_packet_check with invalid sof
static int CheckPacketInvalidSOF(void) {

    uint8_t buffer[EV_PACKET_MAX_LEN] = {0};

    // Manually create a valid packet
    uint8_t test_data[] = {0x01, 0x02, 0x03};
    uint32_t packet_len = sizeof(test_data);
    memcpy(buffer, test_data, packet_len);
    buffer[packet_len + 0] = EV_PACKET_SOF + 1; // ---------------  error sof
    buffer[packet_len + 1] = 0xF1;  //user
    buffer[packet_len + 2] = 0xF2;  // seq
    buffer[packet_len + 3] = 0xF3;  // cmd low byte
    buffer[packet_len + 4] = 0;     // cmd high byte
    buffer[packet_len + 5] = 3;     // len low byte
    buffer[packet_len + 6] = 0;     // len high byte
    buffer[packet_len + 7] = 0;     // sum
    for (uint32_t i = packet_len; i < packet_len + 7; i ++) {
        buffer[packet_len + 7] += buffer[i];
    }
    buffer[packet_len + 7] = (uint8_t) (-buffer[packet_len + 7]);
    uint16_t crc = ev_crc16(buffer, packet_len + 8, EV_PACKET_MAGIC);
    buffer[packet_len + 8] = crc & 0xff;
    buffer[packet_len + 9] = (crc >> 8) & 0xff;

    int result = ev_packet_check(buffer, packet_len + EV_PACKET_TAIL_LEN, NULL);
    EXPECT_EQ(result, -4);
    return 0;
}

// Test ev_packet_check with invalid length
static int CheckPacketLengthMismatch(void) {
    uint8_t buffer[EV_PACKET_MAX_LEN] = {0};

    // Manually create a valid packet
    uint8_t test_data[] = {0x01, 0x02, 0x03};
    uint32_t packet_len = sizeof(test_data);
    memcpy(buffer, test_data, packet_len);
    buffer[packet_len + 0] = EV_PACKET_SOF;
    buffer[packet_len + 1] = 0xF1;  //user
    buffer[packet_len + 2] = 0xF2;  // seq
    buffer[packet_len + 3] = 0xF3;  // cmd low byte
    buffer[packet_len + 4] = 0;     // cmd high byte
    buffer[packet_len + 5] = packet_len + 1; // -------------------error length
    buffer[packet_len + 6] = 0;     // len high byte
    buffer[packet_len + 7] = 0;     // sum
    for (uint32_t i = packet_len; i < packet_len + 7; i ++) {
        buffer[packet_len + 7] += buffer[i];
    }
    buffer[packet_len + 7] = (uint8_t) (-buffer[packet_len + 7]);
    uint16_t crc = ev_crc16(buffer, packet_len + 8, EV_PACKET_MAGIC);
    buffer[packet_len + 8] = crc & 0xff;
    buffer[packet_len + 9] = (crc >> 8) & 0xff;

    int result = ev_packet_check(buffer, packet_len + EV_PACKET_TAIL_LEN, NULL);
    EXPECT_EQ(result, -5);

    return 0;
}

// Test ev_packet_check with invalid sum
static int CheckPacketInvalidSum(void) {
    uint8_t buffer[EV_PACKET_MAX_LEN] = {0};

    // Manually create a valid packet
    uint8_t test_data[] = {0x01, 0x02, 0x03};
    uint32_t packet_len = sizeof(test_data);
    memcpy(buffer, test_data, packet_len);
    buffer[packet_len + 0] = EV_PACKET_SOF;
    buffer[packet_len + 1] = 0xF1;  //user
    buffer[packet_len + 2] = 0xF2;  // seq
    buffer[packet_len + 3] = 0xF3;  // cmd low byte
    buffer[packet_len + 4] = 0;     // cmd high byte
    buffer[packet_len + 5] = 3;     // len low byte
    buffer[packet_len + 6] = 0;     // len high byte
    buffer[packet_len + 7] = 0;     // sum        --------------------error sum

    uint16_t crc = ev_crc16(buffer, packet_len + 8, EV_PACKET_MAGIC);
    buffer[packet_len + 8] = crc & 0xff;
    buffer[packet_len + 9] = (crc >> 8) & 0xff;

    int result = ev_packet_check(buffer, packet_len + EV_PACKET_TAIL_LEN, NULL);
    EXPECT_EQ(result, -6);

    return 0;
}


static void parse_cb(const ev_parser_t *parser, const ev_packet_t *pkt)
{
    (void) pkt;
    int *result = (int *)parser->arg;
    *result = *result + 1;
}
static int ParsePacketValid(void) {
    // Manually create a valid packet
    uint8_t test_data[] = {0x01, 0x02, 0x03};
    uint8_t buffer[sizeof(test_data) + EV_PACKET_TAIL_LEN];
    uint32_t packet_len = sizeof(test_data);
    memcpy(buffer, test_data, packet_len);
    buffer[packet_len + 0] = EV_PACKET_SOF;
    buffer[packet_len + 1] = 0xF1;  //user
    buffer[packet_len + 2] = 0xF2;  // seq
    buffer[packet_len + 3] = 0xF3;  // cmd low byte
    buffer[packet_len + 4] = 0;     // cmd high byte
    buffer[packet_len + 5] = 3;     // len low byte
    buffer[packet_len + 6] = 0;     // len high byte
    buffer[packet_len + 7] = 0;     // sum
    for (uint32_t i = packet_len; i < packet_len + 7; i ++) {
        buffer[packet_len + 7] += buffer[i];
    }
    buffer[packet_len + 7] = (uint8_t) (-buffer[packet_len + 7]);
    uint16_t crc = ev_crc16(buffer, packet_len + 8, EV_PACKET_MAGIC);
    buffer[packet_len + 8] = crc & 0xff;
    buffer[packet_len + 9] = (crc >> 8) & 0xff;

    int result = ev_packet_check(buffer, packet_len + EV_PACKET_TAIL_LEN, NULL);
    EXPECT_EQ(result, 0);

    ev_parser_t parser;
    ev_parser_init(&parser, &result, &parse_cb);

    // parse 5 times
    ev_parser_feed(&parser, buffer, sizeof(buffer));
    ev_parser_feed(&parser, buffer, sizeof(buffer));
    ev_parser_feed(&parser, buffer, sizeof(buffer));
    ev_parser_feed(&parser, buffer, sizeof(buffer));
    ev_parser_feed(&parser, buffer, sizeof(buffer));
    EXPECT_EQ(result, 5);

    return 0;
}

int ev_packet_test(void)
{
    rt_kprintf("MakePacketValidTest: %d\n",  MakePacketValidTest());
    rt_kprintf("MakePacketErrorParam: %d\n",  MakePacketErrorParam());
    rt_kprintf("CheckPacketValid: %d\n",  CheckPacketValid());
    rt_kprintf("CheckPacketTooShort: %d\n",  CheckPacketTooShort());
    rt_kprintf("CheckPacketInvalidSOF: %d\n",  CheckPacketInvalidSOF());
    rt_kprintf("CheckPacketLengthMismatch: %d\n",  CheckPacketLengthMismatch());
    rt_kprintf("CheckPacketInvalidSum: %d\n",  CheckPacketInvalidSum());
    rt_kprintf("ParsePacketValid: %d\n",  ParsePacketValid());
    rt_kprintf("ev_packet_test done\n");
    return 0;
}
MSH_CMD_EXPORT(ev_packet_test, packet test)
#endif
#endif
